package com.woniu.lottery.service.impl;

import com.wn.www.common.entity.dto.LotteryActivityDto;
import com.wn.www.common.exception.BusinessException;
import com.woniu.lottery.entity.*;
import com.woniu.lottery.mapper.LotteryActivityMapper;
import com.woniu.lottery.mapper.LotteryPrizeMapper;
import com.woniu.lottery.service.ILotteryActivityService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.lottery.service.ILotteryPrizeService;
import com.woniu.lottery.service.ILotteryRecordService;
import com.woniu.lottery.strategy.LotteryAlgorithm;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author mane
 * @since 2025-04-13
 */
@Service
public class LotteryActivityServiceImpl extends ServiceImpl<LotteryActivityMapper, LotteryActivity> implements ILotteryActivityService {

    @Autowired
    private LotteryAlgorithm lotteryAlgorithm;

    @Autowired
    private ILotteryRecordService lotteryRecordService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    @Transactional
    public LotteryResult participate(Long userId, Long activityId) {
        // 1. 验证活动状态
        LotteryActivity activity = validateActivity(activityId);

        // 2. 检查用户是否已参与,添加redis缓存
        checkUserParticipation(userId, activityId);

        // 3. 扣减库存(Redis原子操作)
        boolean success = deductStock(activityId);
        if (!success) {
            return LotteryResult.fail("奖品已抽完");
        }

        // 4. 执行抽奖算法
        LotteryContext context = buildContext(userId, activity);
        LotteryResult result = lotteryAlgorithm.draw(context);

        // 5. 保存记录
        LotteryRecord lotteryRecord = new LotteryRecord();
        lotteryRecord.setUserId(userId);
        lotteryRecord.setActivityId(activityId);
        lotteryRecord.setResult(result.isWinner() ? 1 : 0);
        lotteryRecord.setPrizeId(result.getPrizeId());
        lotteryRecord.setCreatedAt(LocalDateTime.now());
        lotteryRecordService.save(lotteryRecord);

        return result;
    }

    @Override
    public String addLotteryActivity(LotteryActivityDto lotteryActivityDto) {
        LotteryActivity lotteryActivity = new LotteryActivity();
        BeanUtils.copyProperties(lotteryActivityDto, lotteryActivity); // 同名属性自动拷贝
        lotteryActivity.setRemainingPrize(lotteryActivityDto.getTotalPrize()); // 特殊字段单独处理
        lotteryActivity.setCreatedAt(LocalDateTime.now());
        lotteryActivity.setUpdatedAt(LocalDateTime.now());
        boolean flag = saveOrUpdate(lotteryActivity);
        return flag?"添加成功":"添加失败";
    }

    //验证活动状态
    private LotteryActivity validateActivity(Long activityId) {
        LotteryActivity activity = getById(activityId);
        if (activity == null) {
            throw new BusinessException("活动不存在");
        }

        LocalDateTime now = LocalDateTime.now();
        if (now.isBefore(activity.getStartTime())) {
            throw new BusinessException("活动未开始");
        }

        if (now.isAfter(activity.getEndTime())) {
            throw new BusinessException("活动已结束");
        }

        if (activity.getStatus() != 1) { // 1表示进行中
            throw new BusinessException("活动不可用");
        }

        return activity;
    }

    //检查用户是否已参与
    private void checkUserParticipation(Long userId, Long activityId) {
        String key = "lottery:participated:" + activityId + ":" + userId;
        Boolean absent = redisTemplate.opsForValue().setIfAbsent(key, "1", Duration.ofMinutes(3));
        if (Boolean.FALSE.equals(absent)) {
            throw new BusinessException("您已参与过本次活动，请明天再来");
        }
    }

    //扣减库存(Redis原子操作)
    private boolean deductStock(Long activityId) {
        String stockKey = "lottery:stock:" + activityId;

        // 先检查key是否存在
        if (Boolean.FALSE.equals(redisTemplate.hasKey(stockKey))) {
            // 初始化库存
            LotteryActivity activity = getById(activityId);
            if (activity == null || activity.getRemainingPrize() <= 0) {
                return false;
            }
            redisTemplate.opsForValue().set(stockKey, activity.getRemainingPrize());
        }

        // 原子递减（返回递减后的值）
        Long remain = redisTemplate.opsForValue().decrement(stockKey);

        if (remain == null) {
            // 极端情况下key被并发删除，重新初始化
            return deductStock(activityId);
        }

        if (remain >= 0) {
            return true;
        } else {
            // 库存不足时恢复
            redisTemplate.opsForValue().increment(stockKey);
            return false;
        }
    }

    @Autowired
    private ILotteryPrizeService lotteryPrizeService;
    // 修改原方法
    private LotteryContext buildContext(Long userId, LotteryActivity activity) {
        List<LotteryPrize> prizes = lotteryPrizeService.getCachedPrizesByActivityId(activity.getId());
        return LotteryContext.builder()
                .userId(userId)
                .activity(activity)
                .prizes(prizes)
                .build();
    }


}
